#pragma once

#include <bitset>
#include "graphics/Rect2D.h"

class GameManager;

/*
	TODO:
	1. serialize input
		- Sync all keyboard state and mouse state (buttons and pos)
	2. Sync input across networked players
	3. handle the input 
		- Rewrite the get classes to use the serialized state
*/

enum Key			   { keyboard_w, keyboard_a, keyboard_s, keyboard_d, keyboard_SPACE, keyboard_LSHIFT, keyboard_pluss, keyboard_minus, KEYS_LEN};
static int key_ind[] = { 'W',		 'A',	     'S',        'D',        GLFW_KEY_SPACE, GLFW_KEY_LEFT_SHIFT, GLFW_KEY_KP_ADD, GLFW_KEY_KP_SUBTRACT};

enum MouseButton		 { mouse_left,			   mouse_right,			   MOUSE_LEN};
static int mouse_ind[] = { GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_RIGHT};

class InputManager
{
public:

	InputManager();
    ~InputManager();

    void update();
    void encode(std::vector<unsigned char>& targetBuf, unsigned int offset);
	void decode(std::vector<unsigned char>& serializedBuf);
    bool isKeyClicked(Key key);
	static bool isKeyClickedLocal(int key);
    bool isKeyPressed(Key key);
    bool isMouseClicked(MouseButton mouseButton);
    bool isMousePressed(MouseButton mouseButton);
    glm::dvec2 getMousePos();
    glm::dvec2 getMouseMoveDelta() { return mouseMoveDelta; }
 	
private:
    
    glm::dvec2 initialMousePos;
    glm::dvec2 mouseMoveDelta;
 	//std::vector<unsigned int> keys;
    static const int GAME_KEY_C = 0;
    static const int N_KEYS = 1;
    std::bitset<KEYS_LEN> keyPrevList;
    std::bitset<8>    mouseButPrevList;

	std::vector<int> keyboardState;
	std::vector<int> mouseButtonState;
	double			 mousePosState[2];
};

class BoxSelector
{
public:
	BoxSelector(InputManager* input) : input(input), rightMouseHeld(false), selectionReady(false), legalBox(false) {}
	void update() {
		if (input->isMousePressed(mouse_left)) {
			if (rightMouseHeld) {
				currentPos = input->getMousePos();
				graphics.updateGeom(getSelectionBox());
				legalBox = true;
			}
			else { // init selection 
				initalPos = input->getMousePos();
				legalBox = false;
			}
			rightMouseHeld = true;
		} 
		else {
			if (rightMouseHeld) // end selection
				selectionReady = true;
			rightMouseHeld = false;
			legalBox = false;
		}
	}
	void draw()	{
		if (legalBox)
			graphics.draw();
	}
	bool isSelectionReady() {
		return selectionReady; 
	}
	glm::dvec4 getSelectionBox() {
		selectionReady = false;
		glm::dvec4 box(initalPos.x, Game::windowDim.y - initalPos.y, currentPos.x, Game::windowDim.y - currentPos.y);
		if (box[0]>box[2]) {
			double temp = box[0];
			box[0] = box[2];
			box[2] = temp;
		}
		if (box[1]>box[3]) {
			double temp = box[1];
			box[1] = box[3];
			box[3] = temp;
		}
		
		return box;
	}
private:
	bool legalBox;
	bool selectionReady;
	bool rightMouseHeld;
	InputManager* input;
	glm::dvec2 initalPos;
	glm::dvec2 currentPos;
	Rect2D graphics;
};